home *** CD-ROM | disk | FTP | other *** search
/ Aminet 35 / Aminet 35 (2000)(Schatztruhe)[!][Feb 2000].iso / Aminet / game / shoot / ADescentSrc.lha / descent / main / gameseg.c < prev    next >
C/C++ Source or Header  |  1998-04-15  |  58KB  |  1,889 lines

  1. /*
  2. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  3. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  4. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  5. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  6. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  7. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  8. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  9. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  10. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
  11. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  12. */
  13. /*
  14.  * $Source: /usr/CVS/descent/main/gameseg.c,v $
  15.  * $Revision: 1.2 $
  16.  * $Author: tfrieden $
  17.  * $Date: 1998/04/14 23:53:30 $
  18.  * 
  19.  * Functions moved from segment.c to make editor separable from game.
  20.  * 
  21.  * $Log: gameseg.c,v $
  22.  * Revision 1.2  1998/04/14 23:53:30  tfrieden
  23.  * Some changes for multiplayer
  24.  *
  25.  * Revision 1.1.1.1  1998/03/03 15:12:20  nobody
  26.  * reimport after crash from backup
  27.  *
  28.  * Revision 1.1.1.1  1998/02/13  20:20:45  hfrieden
  29.  * Initial Import
  30.  */
  31.  
  32. #include <stdlib.h>
  33. #include <stdio.h>
  34. #include <malloc.h> //for stackavail()
  35. #include <string.h> //  for memset()
  36. #include <bsd/bsd.h>
  37.  
  38. #include "inferno.h"
  39. #include "game.h"
  40. #include "error.h"
  41. #include "mono.h"
  42. #include "vecmat.h"
  43. #include "gameseg.h"
  44. #include "wall.h"
  45. #include "fuelcen.h"
  46. #include "byteswap.h"
  47.  
  48. #define db_printf(a) printf a
  49.  
  50. #pragma off (unreferenced)
  51. static char rcsid[] = "$Id: gameseg.c,v 1.2 1998/04/14 23:53:30 tfrieden Exp $";
  52. #pragma on (unreferenced)
  53.  
  54. // How far a point can be from a plane, and still be "in" the plane
  55. #define PLANE_DIST_TOLERANCE    250
  56.  
  57. // ------------------------------------------------------------------------------------------
  58. // Compute the center point of a side of a segment.
  59. //  The center point is defined to be the average of the 4 points defining the side.
  60. void compute_center_point_on_side(vms_vector *vp,segment *sp,int side)
  61. {
  62.     int         v;
  63.  
  64.     vm_vec_zero(vp);
  65.  
  66.     for (v=0; v<4; v++)
  67.         vm_vec_add2(vp,&Vertices[sp->verts[Side_to_verts[side][v]]]);
  68.  
  69.     vm_vec_scale(vp,F1_0/4);
  70. }
  71.  
  72. // ------------------------------------------------------------------------------------------
  73. // Compute segment center.
  74. //  The center point is defined to be the average of the 8 points defining the segment.
  75. void compute_segment_center(vms_vector *vp,segment *sp)
  76. {
  77.     int         v;
  78.  
  79.     vm_vec_zero(vp);
  80.  
  81.     for (v=0; v<8; v++)
  82.         vm_vec_add2(vp,&Vertices[sp->verts[v]]);
  83.  
  84.     vm_vec_scale(vp,F1_0/8);
  85. }
  86.  
  87. // -----------------------------------------------------------------------------
  88. //  Given two segments, return the side index in the connecting segment which connects to the base segment
  89. //  Optimized by MK on 4/21/94 because it is a 2% load.
  90. int find_connect_side(segment *base_seg, segment *con_seg)
  91. {
  92.     int s;
  93.     short   base_seg_num = base_seg - Segments;
  94.     short *childs = con_seg->children;
  95.  
  96.     for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
  97.         if (*childs++ == base_seg_num)
  98.             return s;
  99.     }
  100.  
  101.  
  102.     // legal to return -1, used in object_move_one(), mk, 06/08/94: Assert(0);      // Illegal -- there is no connecting side between these two segments
  103.     return -1;
  104.  
  105. }
  106.  
  107. // -----------------------------------------------------------------------------------
  108. //  Given a side, return the number of faces
  109. int get_num_faces(side *sidep)
  110. {
  111.     switch (sidep->type) {
  112.         case SIDE_IS_QUAD:  return 1;   break;
  113.         case SIDE_IS_TRI_02:
  114.         case SIDE_IS_TRI_13:    return 2;   break;
  115.         default:
  116.             Error("Illegal type = %i\n", sidep->type);
  117.             break;
  118.     }
  119. }
  120.  
  121. // Fill in array with four absolute point numbers for a given side
  122. void get_side_verts(short *vertlist,int segnum,int sidenum)
  123. {
  124.     int i;
  125.     byte  *sv = Side_to_verts[sidenum];
  126.     short   *vp = Segments[segnum].verts;
  127.  
  128.     for (i=4; i--;)
  129.         vertlist[i] = vp[sv[i]];
  130. }
  131.  
  132.  
  133. #ifdef EDITOR
  134. // -----------------------------------------------------------------------------------
  135. //  Create all vertex lists (1 or 2) for faces on a side.
  136. //  Sets:
  137. //      num_faces       number of lists
  138. //      vertices            vertices in all (1 or 2) faces
  139. //  If there is one face, it has 4 vertices.
  140. //  If there are two faces, they both have three vertices, so face #0 is stored in vertices 0,1,2,
  141. //  face #1 is stored in vertices 3,4,5.
  142. // Note: these are not absolute vertex numbers, but are relative to the segment
  143. // Note:  for triagulated sides, the middle vertex of each trianle is the one NOT
  144. //   adjacent on the diagonal edge
  145. void create_all_vertex_lists(int *num_faces, int *vertices, int segnum, int sidenum)
  146. {
  147.     side    *sidep = &Segments[segnum].sides[sidenum];
  148.     int  *sv = Side_to_verts_int[sidenum];
  149.  
  150.     Assert((segnum <= Highest_segment_index) && (segnum >= 0));
  151.     Assert((sidenum >= 0) && (sidenum < 6));
  152.  
  153.     switch (sidep->type) {
  154.         case SIDE_IS_QUAD:
  155.  
  156.             vertices[0] = sv[0];
  157.             vertices[1] = sv[1];
  158.             vertices[2] = sv[2];
  159.             vertices[3] = sv[3];
  160.  
  161.             *num_faces = 1;
  162.             break;
  163.         case SIDE_IS_TRI_02:
  164.             *num_faces = 2;
  165.  
  166.             vertices[0] = sv[0];
  167.             vertices[1] = sv[1];
  168.             vertices[2] = sv[2];
  169.  
  170.             vertices[3] = sv[2];
  171.             vertices[4] = sv[3];
  172.             vertices[5] = sv[0];
  173.  
  174.             //IMPORTANT: DON'T CHANGE THIS CODE WITHOUT CHANGING GET_SEG_MASKS()
  175.             //CREATE_ABS_VERTEX_LISTS(), CREATE_ALL_VERTEX_LISTS(), CREATE_ALL_VERTNUM_LISTS()
  176.             break;
  177.         case SIDE_IS_TRI_13:
  178.             *num_faces = 2;
  179.  
  180.             vertices[0] = sv[3];
  181.             vertices[1] = sv[0];
  182.             vertices[2] = sv[1];
  183.  
  184.             vertices[3] = sv[1];
  185.             vertices[4] = sv[2];
  186.             vertices[5] = sv[3];
  187.  
  188.             //IMPORTANT: DON'T CHANGE THIS CODE WITHOUT CHANGING GET_SEG_MASKS()
  189.             //CREATE_ABS_VERTEX_LISTS(), CREATE_ALL_VERTEX_LISTS(), CREATE_ALL_VERTNUM_LISTS()
  190.             break;
  191.         default:
  192.             Error("Illegal side type, type = %i, segment # = %i, side # = %i\n", sidep->type, segnum, sidenum);
  193.             break;
  194.     }
  195.  
  196. }
  197. #endif
  198.  
  199. // -----------------------------------------------------------------------------------
  200. // Like create all vertex lists, but returns the vertnums (relative to
  201. // the side) for each of the faces that make up the side.  
  202. //  If there is one face, it has 4 vertices.
  203. //  If there are two faces, they both have three vertices, so face #0 is stored in vertices 0,1,2,
  204. //  face #1 is stored in vertices 3,4,5.
  205. void create_all_vertnum_lists(int *num_faces, int *vertnums, int segnum, int sidenum)
  206. {
  207.     side    *sidep = &Segments[segnum].sides[sidenum];
  208.  
  209.     Assert((segnum <= Highest_segment_index) && (segnum >= 0));
  210.  
  211.     switch (sidep->type) {
  212.         case SIDE_IS_QUAD:
  213.  
  214.             vertnums[0] = 0;
  215.             vertnums[1] = 1;
  216.             vertnums[2] = 2;
  217.             vertnums[3] = 3;
  218.  
  219.             *num_faces = 1;
  220.             break;
  221.         case SIDE_IS_TRI_02:
  222.             *num_faces = 2;
  223.  
  224.             vertnums[0] = 0;
  225.             vertnums[1] = 1;
  226.             vertnums[2] = 2;
  227.  
  228.             vertnums[3] = 2;
  229.             vertnums[4] = 3;
  230.             vertnums[5] = 0;
  231.  
  232.             //IMPORTANT: DON'T CHANGE THIS CODE WITHOUT CHANGING GET_SEG_MASKS()
  233.             //CREATE_ABS_VERTEX_LISTS(), CREATE_ALL_VERTEX_LISTS(), CREATE_ALL_VERTNUM_LISTS()
  234.             break;
  235.         case SIDE_IS_TRI_13:
  236.             *num_faces = 2;
  237.  
  238.             vertnums[0] = 3;
  239.             vertnums[1] = 0;
  240.             vertnums[2] = 1;
  241.  
  242.             vertnums[3] = 1;
  243.             vertnums[4] = 2;
  244.             vertnums[5] = 3;
  245.  
  246.             //IMPORTANT: DON'T CHANGE THIS CODE WITHOUT CHANGING GET_SEG_MASKS()
  247.             //CREATE_ABS_VERTEX_LISTS(), CREATE_ALL_VERTEX_LISTS(), CREATE_ALL_VERTNUM_LISTS()
  248.             break;
  249.         default:
  250.             Error("Illegal side type, type = %i, segment # = %i, side # = %i\n", sidep->type, segnum, sidenum);
  251.             break;
  252.     }
  253.  
  254. }
  255.  
  256. // -----
  257. //like create_all_vertex_lists(), but generate absolute point numbers
  258. void create_abs_vertex_lists(int *num_faces, int *vertices, int segnum, int sidenum)
  259. {
  260.     short   *vp = Segments[segnum].verts;
  261.     side    *sidep = &Segments[segnum].sides[sidenum];
  262.     int  *sv = Side_to_verts_int[sidenum];
  263.  
  264.     Assert((segnum <= Highest_segment_index) && (segnum >= 0));
  265.     
  266.     switch (sidep->type) {
  267.         case SIDE_IS_QUAD:
  268.  
  269.             vertices[0] = vp[sv[0]];
  270.             vertices[1] = vp[sv[1]];
  271.             vertices[2] = vp[sv[2]];
  272.             vertices[3] = vp[sv[3]];
  273.  
  274.             *num_faces = 1;
  275.             break;
  276.         case SIDE_IS_TRI_02:
  277.             *num_faces = 2;
  278.  
  279.             vertices[0] = vp[sv[0]];
  280.             vertices[1] = vp[sv[1]];
  281.             vertices[2] = vp[sv[2]];
  282.  
  283.             vertices[3] = vp[sv[2]];
  284.             vertices[4] = vp[sv[3]];
  285.             vertices[5] = vp[sv[0]];
  286.  
  287.             //IMPORTANT: DON'T CHANGE THIS CODE WITHOUT CHANGING GET_SEG_MASKS(),
  288.             //CREATE_ABS_VERTEX_LISTS(), CREATE_ALL_VERTEX_LISTS(), CREATE_ALL_VERTNUM_LISTS()
  289.             break;
  290.         case SIDE_IS_TRI_13:
  291.             *num_faces = 2;
  292.  
  293.             vertices[0] = vp[sv[3]];
  294.             vertices[1] = vp[sv[0]];
  295.             vertices[2] = vp[sv[1]];
  296.  
  297.             vertices[3] = vp[sv[1]];
  298.             vertices[4] = vp[sv[2]];
  299.             vertices[5] = vp[sv[3]];
  300.  
  301.             //IMPORTANT: DON'T CHANGE THIS CODE WITHOUT CHANGING GET_SEG_MASKS()
  302.             //CREATE_ABS_VERTEX_LISTS(), CREATE_ALL_VERTEX_LISTS(), CREATE_ALL_VERTNUM_LISTS()
  303.             break;
  304.         default:
  305.             Error("Illegal side type, type = %i, segment # = %i, side # = %i\n", sidep->type, segnum, sidenum);
  306.             break;
  307.     }
  308.  
  309. }
  310.  
  311.  
  312. //returns 3 different bitmasks with info telling if this sphere is in
  313. //this segment.  See segmasks structure for info on fields   
  314. segmasks get_seg_masks(vms_vector *checkp,int segnum,fix rad)
  315. {
  316.     int         sn,facebit,sidebit;
  317.     segmasks        masks;
  318.     int         num_faces;
  319.     int         vertex_list[6];
  320.     segment     *seg;
  321.  
  322.     Assert((segnum <= Highest_segment_index) && (segnum >= 0));
  323.  
  324.     seg = &Segments[segnum];
  325.  
  326.     //check point against each side of segment. return bitmask
  327.  
  328.     masks.sidemask = masks.facemask = masks.centermask = 0;
  329.  
  330.     for (sn=0,facebit=sidebit=1;sn<6;sn++,sidebit<<=1) {
  331.         #ifndef COMPACT_SEGS
  332.         side    *s = &seg->sides[sn];
  333.         #endif
  334.         int side_pokes_out;
  335.         int vertnum,fn;
  336.         
  337.         // Get number of faces on this side, and at vertex_list, store vertices.
  338.         //  If one face, then vertex_list indicates a quadrilateral.
  339.         //  If two faces, then 0,1,2 define one triangle, 3,4,5 define the second.
  340.         create_abs_vertex_lists( &num_faces, vertex_list, segnum, sn);
  341.  
  342.         //ok...this is important.  If a side has 2 faces, we need to know if
  343.         //those faces form a concave or convex side.  If the side pokes out,
  344.         //then a point is on the back of the side if it is behind BOTH faces,
  345.         //but if the side pokes in, a point is on the back if behind EITHER face.
  346.  
  347.         if (num_faces==2) {
  348.             fix dist;
  349.             int side_count,center_count;
  350.             #ifdef COMPACT_SEGS
  351.             vms_vector normals[2];
  352.             #endif
  353.  
  354.             vertnum = min(vertex_list[0],vertex_list[2]);
  355.             
  356.             #ifdef COMPACT_SEGS
  357.             get_side_normals(seg, sn, &normals[0], &normals[1] );
  358.             #endif
  359.             
  360.             if (vertex_list[4] < vertex_list[1])
  361.                 #ifdef COMPACT_SEGS
  362.                     dist = vm_dist_to_plane(&Vertices[vertex_list[4]],&normals[0],&Vertices[vertnum]);
  363.                 #else
  364.                     dist = vm_dist_to_plane(&Vertices[vertex_list[4]],&s->normals[0],&Vertices[vertnum]);
  365.                 #endif
  366.             else
  367.                 #ifdef COMPACT_SEGS
  368.                     dist = vm_dist_to_plane(&Vertices[vertex_list[1]],&normals[1],&Vertices[vertnum]);
  369.                 #else
  370.                     dist = vm_dist_to_plane(&Vertices[vertex_list[1]],&s->normals[1],&Vertices[vertnum]);
  371.                 #endif
  372.  
  373.             side_pokes_out = (dist > PLANE_DIST_TOLERANCE);
  374.  
  375.             side_count = center_count = 0;
  376.  
  377.             for (fn=0;fn<2;fn++,facebit<<=1) {
  378.  
  379.                 #ifdef COMPACT_SEGS
  380.                     dist = vm_dist_to_plane(checkp, &normals[fn], &Vertices[vertnum]);
  381.                 #else
  382.                     dist = vm_dist_to_plane(checkp, &s->normals[fn], &Vertices[vertnum]);
  383.                 #endif
  384.  
  385.                 if (dist < -PLANE_DIST_TOLERANCE)   //in front of face
  386.                     center_count++;
  387.  
  388.                 if (dist-rad < -PLANE_DIST_TOLERANCE) {
  389.                     masks.facemask |= facebit;
  390.                     side_count++;
  391.                 }
  392.             }
  393.  
  394.             if (!side_pokes_out) {      //must be behind both faces
  395.  
  396.                 if (side_count==2)
  397.                     masks.sidemask |= sidebit;
  398.  
  399.                 if (center_count==2)
  400.                     masks.centermask |= sidebit;
  401.  
  402.             }
  403.             else {                          //must be behind at least one face
  404.  
  405.                 if (side_count)
  406.                     masks.sidemask |= sidebit;
  407.  
  408.                 if (center_count)
  409.                     masks.centermask |= sidebit;
  410.  
  411.             }
  412.  
  413.  
  414.         }
  415.         else {              //only one face on this side
  416.             fix dist;
  417.             int i;
  418.             #ifdef COMPACT_SEGS         
  419.             vms_vector normal;
  420.             #endif
  421.  
  422.             //use lowest point number
  423.  
  424.             vertnum = vertex_list[0];
  425.             for (i=1;i<4;i++)
  426.                 if (vertex_list[i] < vertnum)
  427.                     vertnum = vertex_list[i];
  428.  
  429.             #ifdef COMPACT_SEGS
  430.                 get_side_normal(seg, sn, 0, &normal );
  431.                 dist = vm_dist_to_plane(checkp, &normal, &Vertices[vertnum]);
  432.             #else
  433.                 dist = vm_dist_to_plane(checkp, &s->normals[0], &Vertices[vertnum]);
  434.             #endif
  435.  
  436.     
  437.             if (dist < -PLANE_DIST_TOLERANCE)
  438.                 masks.centermask |= sidebit;
  439.     
  440.             if (dist-rad < -PLANE_DIST_TOLERANCE) {
  441.                 masks.facemask |= facebit;
  442.                 masks.sidemask |= sidebit;
  443.             }
  444.  
  445.             facebit <<= 2;
  446.         }
  447.  
  448.     }
  449.  
  450.     return masks;
  451.  
  452. }
  453.  
  454. //this was converted from get_seg_masks()...it fills in an array of 6
  455. //elements for the distace behind each side, or zero if not behind
  456. //only gets centermask, and assumes zero rad 
  457. ubyte get_side_dists(vms_vector *checkp,int segnum,fix *side_dists)
  458. {
  459.     int         sn,facebit,sidebit;
  460.     ubyte           mask;
  461.     int         num_faces;
  462.     int         vertex_list[6];
  463.     segment     *seg;
  464.  
  465.     Assert((segnum <= Highest_segment_index) && (segnum >= 0));
  466.  
  467.     seg = &Segments[segnum];
  468.  
  469.     //check point against each side of segment. return bitmask
  470.  
  471.     mask = 0;
  472.  
  473.     for (sn=0,facebit=sidebit=1;sn<6;sn++,sidebit<<=1) {
  474.         #ifndef COMPACT_SEGS
  475.         side    *s = &seg->sides[sn];
  476.         #endif
  477.         int side_pokes_out;
  478.         int fn;
  479.  
  480.         side_dists[sn] = 0;
  481.  
  482.         // Get number of faces on this side, and at vertex_list, store vertices.
  483.         //  If one face, then vertex_list indicates a quadrilateral.
  484.         //  If two faces, then 0,1,2 define one triangle, 3,4,5 define the second.
  485.         create_abs_vertex_lists( &num_faces, vertex_list, segnum, sn);
  486.  
  487.         //ok...this is important.  If a side has 2 faces, we need to know if
  488.         //those faces form a concave or convex side.  If the side pokes out,
  489.         //then a point is on the back of the side if it is behind BOTH faces,
  490.         //but if the side pokes in, a point is on the back if behind EITHER face.
  491.  
  492.         if (num_faces==2) {
  493.             fix dist;
  494.             int center_count;
  495.             int vertnum;
  496.             #ifdef COMPACT_SEGS
  497.             vms_vector normals[2];
  498.             #endif
  499.  
  500.             vertnum = min(vertex_list[0],vertex_list[2]);
  501.  
  502.             #ifdef COMPACT_SEGS
  503.             get_side_normals(seg, sn, &normals[0], &normals[1] );
  504.             #endif
  505.  
  506.             if (vertex_list[4] < vertex_list[1])
  507.                 #ifdef COMPACT_SEGS
  508.                     dist = vm_dist_to_plane(&Vertices[vertex_list[4]],&normals[0],&Vertices[vertnum]);
  509.                 #else
  510.                     dist = vm_dist_to_plane(&Vertices[vertex_list[4]],&s->normals[0],&Vertices[vertnum]);
  511.                 #endif
  512.             else
  513.                 #ifdef COMPACT_SEGS
  514.                     dist = vm_dist_to_plane(&Vertices[vertex_list[1]],&normals[1],&Vertices[vertnum]);
  515.                 #else
  516.                     dist = vm_dist_to_plane(&Vertices[vertex_list[1]],&s->normals[1],&Vertices[vertnum]);
  517.                 #endif
  518.  
  519.             side_pokes_out = (dist > PLANE_DIST_TOLERANCE);
  520.  
  521.             center_count = 0;
  522.  
  523.             for (fn=0;fn<2;fn++,facebit<<=1) {
  524.  
  525.                 #ifdef COMPACT_SEGS
  526.                     dist = vm_dist_to_plane(checkp, &normals[fn], &Vertices[vertnum]);
  527.                 #else
  528.                     dist = vm_dist_to_plane(checkp, &s->normals[fn], &Vertices[vertnum]);
  529.                 #endif
  530.  
  531.                 if (dist < -PLANE_DIST_TOLERANCE) { //in front of face
  532.                     center_count++;
  533.                     side_dists[sn] += dist;
  534.                 }
  535.  
  536.             }
  537.  
  538.             if (!side_pokes_out) {      //must be behind both faces
  539.  
  540.                 if (center_count==2) {
  541.                     mask |= sidebit;
  542.                     side_dists[sn] /= 2;        //get average
  543.                 }
  544.                     
  545.  
  546.             }
  547.             else {                          //must be behind at least one face
  548.  
  549.                 if (center_count) {
  550.                     mask |= sidebit;
  551.                     if (center_count==2)
  552.                         side_dists[sn] /= 2;        //get average
  553.  
  554.                 }
  555.             }
  556.  
  557.  
  558.         }
  559.         else {              //only one face on this side
  560.             fix dist;
  561.             int i,vertnum;
  562.             #ifdef COMPACT_SEGS         
  563.             vms_vector normal;
  564.             #endif
  565.  
  566.  
  567.             //use lowest point number
  568.  
  569.             vertnum = vertex_list[0];
  570.             for (i=1;i<4;i++)
  571.                 if (vertex_list[i] < vertnum)
  572.                     vertnum = vertex_list[i];
  573.  
  574.             #ifdef COMPACT_SEGS
  575.                 get_side_normal(seg, sn, 0, &normal );
  576.                 dist = vm_dist_to_plane(checkp, &normal, &Vertices[vertnum]);
  577.             #else
  578.                 dist = vm_dist_to_plane(checkp, &s->normals[0], &Vertices[vertnum]);
  579.             #endif
  580.     
  581.             if (dist < -PLANE_DIST_TOLERANCE) {
  582.                 mask |= sidebit;
  583.                 side_dists[sn] = dist;
  584.             }
  585.     
  586.             facebit <<= 2;
  587.         }
  588.  
  589.     }
  590.  
  591.     return mask;
  592.  
  593. }
  594.  
  595. #ifndef NDEBUG 
  596. #ifndef COMPACT_SEGS
  597. //returns true if errors detected
  598. int check_norms(int segnum,int sidenum,int facenum,int csegnum,int csidenum,int cfacenum)
  599. {
  600.     vms_vector *n0,*n1;
  601.  
  602.     n0 = &Segments[segnum].sides[sidenum].normals[facenum];
  603.     n1 = &Segments[csegnum].sides[csidenum].normals[cfacenum];
  604.  
  605.     if (n0->x != -n1->x  ||  n0->y != -n1->y  ||  n0->z != -n1->z) {
  606.         mprintf((0,"Seg %x, side %d, norm %d doesn't match seg %x, side %d, norm %d:\n"
  607.                 "   %8x %8x %8x\n"
  608.                 "   %8x %8x %8x (negated)\n",
  609.                 segnum,sidenum,facenum,csegnum,csidenum,cfacenum,
  610.                 n0->x,n0->y,n0->z,-n1->x,-n1->y,-n1->z));
  611.         return 1;
  612.     }
  613.     else
  614.         return 0;
  615. }
  616.  
  617. //heavy-duty error checking
  618. int check_segment_connections(void)
  619. {
  620.     int segnum,sidenum;
  621.     int errors=0;
  622.  
  623.     for (segnum=0;segnum<=Highest_segment_index;segnum++) {
  624.         segment *seg;
  625.  
  626.         seg = &Segments[segnum];
  627.  
  628.         for (sidenum=0;sidenum<6;sidenum++) {
  629.             side *s;
  630.             segment *cseg;
  631.             side *cs;
  632.             int num_faces,csegnum,csidenum,con_num_faces;
  633.             int vertex_list[6],con_vertex_list[6];
  634.  
  635.             s = &seg->sides[sidenum];
  636.  
  637.             create_abs_vertex_lists( &num_faces, vertex_list, segnum, sidenum);
  638.  
  639.             csegnum = seg->children[sidenum];
  640.  
  641.             if (csegnum >= 0) {
  642.                 cseg = &Segments[csegnum];
  643.                 csidenum = find_connect_side(seg,cseg);
  644.  
  645.                 if (csidenum == -1) {
  646.                     mprintf((0,"Could not find connected side for seg %x back to seg %x, side %d\n",csegnum,segnum,sidenum));
  647.                     errors = 1;
  648.                     continue;
  649.                 }
  650.  
  651.                 cs = &cseg->sides[csidenum];
  652.  
  653.                 create_abs_vertex_lists( &con_num_faces, con_vertex_list, csegnum, csidenum);
  654.  
  655.                 if (con_num_faces != num_faces) {
  656.                     mprintf((0,"Seg %x, side %d: num_faces (%d) mismatch with seg %x, side %d (%d)\n",segnum,sidenum,num_faces,csegnum,csidenum,con_num_faces));
  657.                     errors = 1;
  658.                 }
  659.                 else
  660.                     if (num_faces == 1) {
  661.                         int t;
  662.  
  663.                         for (t=0;t<4 && con_vertex_list[t]!=vertex_list[0];t++);
  664.  
  665.                         if (t==4 ||
  666.                              vertex_list[0] != con_vertex_list[t] ||
  667.                              vertex_list[1] != con_vertex_list[(t+3)%4] ||
  668.                              vertex_list[2] != con_vertex_list[(t+2)%4] ||
  669.                              vertex_list[3] != con_vertex_list[(t+1)%4]) {
  670.                             mprintf((0,"Seg %x, side %d: vertex list mismatch with seg %x, side %d\n"
  671.                                     "  %x %x %x %x\n"
  672.                                     "  %x %x %x %x\n",
  673.                                     segnum,sidenum,csegnum,csidenum,
  674.                                     vertex_list[0],vertex_list[1],vertex_list[2],vertex_list[3],
  675.                                     con_vertex_list[0],con_vertex_list[1],con_vertex_list[2],con_vertex_list[3]));
  676.                             errors = 1;
  677.                         }
  678.                         else
  679.                             errors |= check_norms(segnum,sidenum,0,csegnum,csidenum,0);
  680.     
  681.                     }
  682.                     else {
  683.     
  684.                         if (vertex_list[1] == con_vertex_list[1]) {
  685.         
  686.                             if (vertex_list[4] != con_vertex_list[4] ||
  687.                                  vertex_list[0] != con_vertex_list[2] ||
  688.                                  vertex_list[2] != con_vertex_list[0] ||
  689.                                  vertex_list[3] != con_vertex_list[5] ||
  690.                                  vertex_list[5] != con_vertex_list[3]) {
  691.                                 mprintf((0,"Seg %x, side %d: vertex list mismatch with seg %x, side %d\n"
  692.                                         "  %x %x %x  %x %x %x\n"
  693.                                         "  %x %x %x  %x %x %x\n",
  694.                                         segnum,sidenum,csegnum,csidenum,
  695.                                         vertex_list[0],vertex_list[1],vertex_list[2],vertex_list[3],vertex_list[4],vertex_list[5],
  696.                                         con_vertex_list[0],con_vertex_list[1],con_vertex_list[2],con_vertex_list[3],con_vertex_list[4],con_vertex_list[5]));
  697.                                 mprintf((0,"Changing seg:side %4i:%i from %i to %i\n", csegnum, csidenum, Segments[csegnum].sides[csidenum].type, 5-Segments[csegnum].sides[csidenum].type));
  698.                                 Segments[csegnum].sides[csidenum].type = 5-Segments[csegnum].sides[csidenum].type;
  699.                             } else {
  700.                                 errors |= check_norms(segnum,sidenum,0,csegnum,csidenum,0);
  701.                                 errors |= check_norms(segnum,sidenum,1,csegnum,csidenum,1);
  702.                             }
  703.     
  704.                         } else {
  705.         
  706.                             if (vertex_list[1] != con_vertex_list[4] ||
  707.                                  vertex_list[4] != con_vertex_list[1] ||
  708.                                  vertex_list[0] != con_vertex_list[5] ||
  709.                                  vertex_list[5] != con_vertex_list[0] ||
  710.                                  vertex_list[2] != con_vertex_list[3] ||
  711.                                  vertex_list[3] != con_vertex_list[2]) {
  712.                                 mprintf((0,"Seg %x, side %d: vertex list mismatch with seg %x, side %d\n"
  713.                                         "  %x %x %x  %x %x %x\n"
  714.                                         "  %x %x %x  %x %x %x\n",
  715.                                         segnum,sidenum,csegnum,csidenum,
  716.                                         vertex_list[0],vertex_list[1],vertex_list[2],vertex_list[3],vertex_list[4],vertex_list[5],
  717.                                         con_vertex_list[0],con_vertex_list[1],con_vertex_list[2],con_vertex_list[3],con_vertex_list[4],vertex_list[5]));
  718.                                 mprintf((0,"Changing seg:side %4i:%i from %i to %i\n", csegnum, csidenum, Segments[csegnum].sides[csidenum].type, 5-Segments[csegnum].sides[csidenum].type));
  719.                                 Segments[csegnum].sides[csidenum].type = 5-Segments[csegnum].sides[csidenum].type;
  720.                             } else {
  721.                                 errors |= check_norms(segnum,sidenum,0,csegnum,csidenum,1);
  722.                                 errors |= check_norms(segnum,sidenum,1,csegnum,csidenum,0);
  723.                             }
  724.                         }
  725.                     }
  726.             }
  727.         }
  728.     }
  729.  
  730.     // mprintf((0,"\n DONE \n"));
  731.  
  732.     return errors;
  733.  
  734. }
  735. #endif
  736. #endif
  737.  
  738. #ifdef EDITOR
  739. int Doing_lighting_hack_flag=0;
  740. #else
  741. #define Doing_lighting_hack_flag 0
  742. #endif
  743.  
  744. //figure out what seg the given point is in, tracing through segments
  745. //returns segment number, or -1 if can't find segment
  746. int trace_segs(vms_vector *p0,int oldsegnum)
  747. {
  748.     int centermask;
  749.     segment *seg;
  750.     fix side_dists[6];
  751.  
  752.     Assert((oldsegnum <= Highest_segment_index) && (oldsegnum >= 0));
  753.  
  754.     /*
  755.     if (stackavail() < 1024) {      //if no debugging, we'll get past assert
  756.  
  757.         #ifndef NDEBUG
  758.         if (!Doing_lighting_hack_flag)
  759.             Int3(); // Please get Matt, or if you cannot, then type 
  760.                         // "?p0->xyz,segnum" at the DBG prompt, write down
  761.                         // the values (a 3-element vector and a segment number), 
  762.                         // and make a copy of the mine you are playing.
  763.         #endif
  764.  
  765.         return oldsegnum;               //just say we're in this segment and be done with it
  766.     }
  767.     */
  768.  
  769.  
  770.     centermask = get_side_dists(p0,oldsegnum,side_dists);       //check old segment
  771.  
  772.     if (centermask == 0)        //we're in the old segment
  773.  
  774.         return oldsegnum;       //..say so
  775.  
  776.     else {                      //not in old seg.  trace through to find seg
  777.         int biggest_side;
  778.  
  779.         do {
  780.             int sidenum,bit;
  781.             fix biggest_val;
  782.  
  783.             seg = &Segments[oldsegnum];
  784.  
  785.             biggest_side = -1; biggest_val = 0;
  786.  
  787.             for (sidenum=0,bit=1;sidenum<6;sidenum++,bit<<=1)
  788.                 if ((centermask&bit) && (seg->children[sidenum]>-1))
  789.                     if (side_dists[sidenum] < biggest_val) {
  790.                         biggest_val = side_dists[sidenum];
  791.                         biggest_side = sidenum;
  792.                     }
  793.  
  794.             if (biggest_side != -1) {
  795.                 int check;
  796.  
  797.                 side_dists[biggest_side] = 0;
  798.  
  799.                 check = trace_segs(p0,seg->children[biggest_side]); //trace into adjacent segment
  800.  
  801.                 if (check != -1)        //we've found a segment
  802.                     return check;   
  803.             }
  804.  
  805.  
  806.         } while (biggest_side!=-1);
  807.  
  808.         return -1;      //we haven't found a segment
  809.     }
  810.  
  811. }
  812.  
  813.  
  814. int Exhaustive_count=0, Exhaustive_failed_count=0;
  815.  
  816. //Tries to find a segment for a point, in the following way:
  817. // 1. Check the given segment
  818. // 2. Recursively trace through attached segments
  819. // 3. Check all the segmentns
  820. //Returns segnum if found, or -1
  821. int find_point_seg(vms_vector *p,int segnum)
  822. {
  823.     int newseg;
  824.  
  825.     //allow segnum==-1, meaning we have no idea what segment point is in
  826.     Assert((segnum <= Highest_segment_index) && (segnum >= -1));
  827.  
  828.     if (segnum != -1) {
  829.         newseg = trace_segs(p,segnum);
  830.  
  831.         if (newseg != -1)           //we found a segment!
  832.             return newseg;
  833.     }
  834.  
  835.     //couldn't find via attached segs, so search all segs
  836.  
  837.     //  MK: 10/15/94
  838.     //  This Doing_lighting_hack_flag thing added by mk because the hundreds of scrolling messages were
  839.     //  slowing down lighting, and in about 98% of cases, it would just return -1 anyway.
  840.     //  Matt: This really should be fixed, though.  We're probably screwing up our lighting in a few places.
  841.     if (!Doing_lighting_hack_flag) {
  842.         mprintf((1,"Warning: doing exhaustive search to find point segment (%i times)\n", ++Exhaustive_count));
  843.  
  844.         for (newseg=0;newseg <= Highest_segment_index;newseg++)
  845.             if (get_seg_masks(p,newseg,0).centermask == 0)
  846.                 return newseg;
  847.  
  848.         mprintf((1,"Warning: could not find point segment (%i times)\n", ++Exhaustive_failed_count));
  849.  
  850.         return -1;      //no segment found
  851.     } else
  852.         return -1;
  853. }
  854.  
  855.  
  856. //--repair-- // ------------------------------------------------------------------------------
  857. //--repair-- void clsd_repair_center(int segnum)
  858. //--repair-- {
  859. //--repair--    int sidenum;
  860. //--repair-- 
  861. //--repair--    //  --- Set repair center bit for all repair center segments.
  862. //--repair--    if (Segments[segnum].special == SEGMENT_IS_REPAIRCEN) {
  863. //--repair--        Lsegments[segnum].special_type |= SS_REPAIR_CENTER;
  864. //--repair--        Lsegments[segnum].special_segment = segnum;
  865. //--repair--    }
  866. //--repair-- 
  867. //--repair--    //  --- Set repair center bit for all segments adjacent to a repair center.
  868. //--repair--    for (sidenum=0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) {
  869. //--repair--        int s = Segments[segnum].children[sidenum];
  870. //--repair-- 
  871. //--repair--        if ( (s != -1) && (Segments[s].special==SEGMENT_IS_REPAIRCEN) ) {
  872. //--repair--            Lsegments[segnum].special_type |= SS_REPAIR_CENTER;
  873. //--repair--            Lsegments[segnum].special_segment = s;
  874. //--repair--        }
  875. //--repair--    }
  876. //--repair-- }
  877.  
  878. //--repair-- // ------------------------------------------------------------------------------
  879. //--repair-- // --- Set destination points for all Materialization centers.
  880. //--repair-- void clsd_materialization_center(int segnum)
  881. //--repair-- {
  882. //--repair--    if (Segments[segnum].special == SEGMENT_IS_ROBOTMAKER) {
  883. //--repair-- 
  884. //--repair--    }
  885. //--repair-- }
  886. //--repair-- 
  887. //--repair-- int    Lsegment_highest_segment_index, Lsegment_highest_vertex_index;
  888. //--repair-- 
  889. //--repair-- // ------------------------------------------------------------------------------
  890. //--repair-- // Create data specific to mine which doesn't get written to disk.
  891. //--repair-- // Highest_segment_index and Highest_object_index must be valid.
  892. //--repair-- // 07/21:  set repair center bit
  893. //--repair-- void create_local_segment_data(void)
  894. //--repair-- {
  895. //--repair--    int segnum;
  896. //--repair-- 
  897. //--repair--    //  --- Initialize all Lsegments.
  898. //--repair--    for (segnum=0; segnum <= Highest_segment_index; segnum++) {
  899. //--repair--        Lsegments[segnum].special_type = 0;
  900. //--repair--        Lsegments[segnum].special_segment = -1;
  901. //--repair--    }
  902. //--repair-- 
  903. //--repair--    for (segnum=0; segnum <= Highest_segment_index; segnum++) {
  904. //--repair-- 
  905. //--repair--        clsd_repair_center(segnum);
  906. //--repair--        clsd_materialization_center(segnum);
  907. //--repair--    
  908. //--repair--    }
  909. //--repair-- 
  910. //--repair--    //  Set check variables.
  911. //--repair--    //  In main game loop, make sure these are valid, else Lsegments is not valid.
  912. //--repair--    Lsegment_highest_segment_index = Highest_segment_index;
  913. //--repair--    Lsegment_highest_vertex_index = Highest_vertex_index;
  914. //--repair-- }
  915. //--repair-- 
  916. //--repair-- // ------------------------------------------------------------------------------------------
  917. //--repair-- // Sort of makes sure create_local_segment_data has been called for the currently executing mine.
  918. //--repair-- // It is not failsafe, as you will see if you look at the code.
  919. //--repair-- // Returns 1 if Lsegments appears valid, 0 if not.
  920. //--repair-- int check_lsegments_validity(void)
  921. //--repair-- {
  922. //--repair--    return ((Lsegment_highest_segment_index == Highest_segment_index) && (Lsegment_highest_vertex_index == Highest_vertex_index));
  923. //--repair-- }
  924.  
  925. #define MAX_LOC_POINT_SEGS  64
  926.  
  927. int Connected_segment_distance;
  928.  
  929. //  ----------------------------------------------------------------------------------------------------------
  930. //  Determine whether seg0 and seg1 are reachable in a way that allows sound to pass.
  931. //  Search up to a maximum depth of max_depth.
  932. //  Return the distance.
  933. fix find_connected_distance(vms_vector *p0, int seg0, vms_vector *p1, int seg1, int max_depth, int wid_flag)
  934. {
  935.     int     cur_seg;
  936.     int     sidenum;
  937.     int     qtail = 0, qhead = 0;
  938.     int     i;
  939.     byte        visited[MAX_SEGMENTS];
  940.     seg_seg seg_queue[MAX_SEGMENTS];
  941.     short       depth[MAX_SEGMENTS];
  942.     int     cur_depth;
  943.     int     num_points;
  944.     point_seg   point_segs[MAX_LOC_POINT_SEGS];
  945.     fix     dist;
  946.  
  947.     //  If > this, will overrun point_segs buffer
  948.     if (max_depth > MAX_LOC_POINT_SEGS-2) {
  949.         mprintf((1, "Warning: In find_connected_distance, max_depth = %i, limited to %i\n", max_depth, MAX_LOC_POINT_SEGS-2));
  950.         max_depth = MAX_LOC_POINT_SEGS-2;
  951.     }
  952.  
  953.     if (seg0 == seg1) {
  954.         Connected_segment_distance = 0;
  955.         return vm_vec_dist_quick(p0, p1);
  956.     } else if (find_connect_side(&Segments[seg0], &Segments[seg1]) != -1) {
  957.         Connected_segment_distance = 1;
  958.         return vm_vec_dist_quick(p0, p1);
  959.     }
  960.  
  961.     num_points = 0;
  962.  
  963. //  for (i=0; i<=Highest_segment_index; i++) {
  964. //      visited[i] = 0;
  965. //      depth[i] = 0;
  966. //  }
  967. memset(visited, 0, Highest_segment_index+1);
  968. memset(depth, 0, Highest_segment_index+1);
  969.  
  970.     cur_seg = seg0;
  971.     visited[cur_seg] = 1;
  972.     cur_depth = 0;
  973.  
  974.     while (cur_seg != seg1) {
  975.         segment *segp = &Segments[cur_seg];
  976.  
  977.         for (sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) {
  978.  
  979.             int snum = sidenum;
  980.  
  981.             if (WALL_IS_DOORWAY(segp, snum) & wid_flag) {
  982.                 int this_seg = segp->children[snum];
  983.  
  984.                 if (!visited[this_seg]) {
  985.                     seg_queue[qtail].start = cur_seg;
  986.                     seg_queue[qtail].end = this_seg;
  987.                     visited[this_seg] = 1;
  988.                     depth[qtail++] = cur_depth+1;
  989.                     if (max_depth != -1) {
  990.                         if (depth[qtail-1] == max_depth) {
  991.                             Connected_segment_distance = 1000;
  992.                             return -1;
  993. //                          seg1 = seg_queue[qtail-1].end;
  994. //                          goto fcd_done1;
  995.                         }
  996.                     } else if (this_seg == seg1) {
  997.                         goto fcd_done1;
  998.                     }
  999.                 }
  1000.  
  1001.             }
  1002.         }   //  for (sidenum...
  1003.  
  1004.         if (qhead >= qtail) {
  1005.             Connected_segment_distance = 1000;
  1006.             return -1;
  1007.         }
  1008.  
  1009.         cur_seg = seg_queue[qhead].end;
  1010.         cur_depth = depth[qhead];
  1011.         qhead++;
  1012.  
  1013. fcd_done1: ;
  1014.     }   //  while (cur_seg ...
  1015.  
  1016.     //  Set qtail to the segment which ends at the goal.
  1017.     while (seg_queue[--qtail].end != seg1)
  1018.         if (qtail < 0) {
  1019.             Connected_segment_distance = 1000;
  1020.             return -1;
  1021.         }
  1022.  
  1023.     while (qtail >= 0) {
  1024.         int parent_seg, this_seg;
  1025.  
  1026.         this_seg = seg_queue[qtail].end;
  1027.         parent_seg = seg_queue[qtail].start;
  1028.         point_segs[num_points].segnum = this_seg;
  1029.         compute_segment_center(&point_segs[num_points].point,&Segments[this_seg]);
  1030.         num_points++;
  1031.  
  1032.         if (parent_seg == seg0)
  1033.             break;
  1034.  
  1035.         while (seg_queue[--qtail].end != parent_seg)
  1036.             Assert(qtail >= 0);
  1037.     }
  1038.  
  1039.     point_segs[num_points].segnum = seg0;
  1040.     compute_segment_center(&point_segs[num_points].point,&Segments[seg0]);
  1041.     num_points++;
  1042.  
  1043.     //  Compute distance
  1044. //      mprintf((0, "Path = "));
  1045. //      for (i=0; i<num_points; i++)
  1046. //          mprintf((0, "%2i ", point_segs[i].segnum));
  1047. //      mprintf((0, "\n"));
  1048.  
  1049.     if (num_points == 1) {
  1050.         Connected_segment_distance = num_points;
  1051.         return vm_vec_dist_quick(p0, p1);
  1052.     } else {
  1053.         dist = vm_vec_dist_quick(p1, &point_segs[1].point);
  1054.         dist += vm_vec_dist_quick(p0, &point_segs[num_points-2].point);
  1055.  
  1056. //      mprintf((0, "[%5.1f %2i %2i] [%5.1f %2i %2i] ", 
  1057. //          f2fl(vm_vec_dist_quick(p1, &point_segs[1].point)), seg1, point_segs[1].segnum,
  1058. //          f2fl(vm_vec_dist_quick(p0, &point_segs[num_points-2].point)), point_segs[num_points-2].segnum, seg0));
  1059.  
  1060.         for (i=1; i<num_points-2; i++) {
  1061.             fix ndist;
  1062.             ndist = vm_vec_dist_quick(&point_segs[i].point, &point_segs[i+1].point);
  1063.             dist += ndist;
  1064. //          mprintf((0, "[%5.1f %2i %2i] ", f2fl(ndist), point_segs[i].segnum, point_segs[i+1].segnum));
  1065.         }
  1066.  
  1067. //      mprintf((0, "\n"));
  1068.     }
  1069.  
  1070.     Connected_segment_distance = num_points;
  1071.     return dist;
  1072.  
  1073. }
  1074.  
  1075. //--unused-- int    Max_fcd_depth=30;
  1076.  
  1077. //--unused-- fix fcd_test(void)
  1078. //--unused-- {
  1079. //--unused--    fix rval;
  1080. //--unused-- 
  1081. //--unused--    rval = find_connected_distance(&Objects[0].pos, Objects[0].segnum, &Objects[1].pos, Objects[1].segnum, Max_fcd_depth, WID_RENDPAST_FLAG);
  1082. //--unused-- 
  1083. //--unused--    mprintf((0, "Distance as travelled = %5.1f\n", f2fl(rval)));
  1084. //--unused--    return rval;
  1085. //--unused-- }
  1086.  
  1087. byte convert_to_byte(fix f)
  1088. {
  1089.     if (f >= 0x00010000)
  1090.         return MATRIX_MAX;
  1091.     else if (f <= -0x00010000)
  1092.         return -MATRIX_MAX;
  1093.     else
  1094.         return f >> MATRIX_PRECISION;
  1095. }
  1096.  
  1097. #define VEL_PRECISION 12
  1098.  
  1099. //  Create a shortpos struct from an object.
  1100. //  Extract the matrix into byte values.
  1101. //  Create a position relative to vertex 0 with 1/256 normal "fix" precision.
  1102. //  Stuff segment in a short.
  1103. void create_shortpos(shortpos *spp, object *objp)
  1104. {
  1105.     // int  segnum;
  1106.     byte    *sp;
  1107.     int swap_bytes = 1;
  1108.  
  1109.  
  1110.     sp = spp->bytemat;
  1111.  
  1112.     *sp++ = convert_to_byte(objp->orient.rvec.x);
  1113.     *sp++ = convert_to_byte(objp->orient.uvec.x);
  1114.     *sp++ = convert_to_byte(objp->orient.fvec.x);
  1115.     *sp++ = convert_to_byte(objp->orient.rvec.y);
  1116.     *sp++ = convert_to_byte(objp->orient.uvec.y);
  1117.     *sp++ = convert_to_byte(objp->orient.fvec.y);
  1118.     *sp++ = convert_to_byte(objp->orient.rvec.z);
  1119.     *sp++ = convert_to_byte(objp->orient.uvec.z);
  1120.     *sp++ = convert_to_byte(objp->orient.fvec.z);
  1121.  
  1122.     spp->xo = (objp->pos.x - Vertices[Segments[objp->segnum].verts[0]].x) >> RELPOS_PRECISION;
  1123.     spp->yo = (objp->pos.y - Vertices[Segments[objp->segnum].verts[0]].y) >> RELPOS_PRECISION;
  1124.     spp->zo = (objp->pos.z - Vertices[Segments[objp->segnum].verts[0]].z) >> RELPOS_PRECISION;
  1125.  
  1126.     spp->segment = objp->segnum;
  1127.  
  1128.     spp->velx = (objp->mtype.phys_info.velocity.x) >> VEL_PRECISION;
  1129.     spp->vely = (objp->mtype.phys_info.velocity.y) >> VEL_PRECISION;
  1130.     spp->velz = (objp->mtype.phys_info.velocity.z) >> VEL_PRECISION;
  1131.  
  1132.     if (swap_bytes) {
  1133.         spp->xo = swapshort(spp->xo);
  1134.         spp->yo = swapshort(spp->yo);
  1135.         spp->zo = swapshort(spp->zo);
  1136.         spp->segment = swapshort(spp->segment);
  1137.         spp->velx = swapshort(spp->velx);
  1138.         spp->vely = swapshort(spp->vely);
  1139.         spp->velz = swapshort(spp->velz);
  1140.     }
  1141.  
  1142.  
  1143. //  mprintf((0, "Matrix: %08x %08x %08x    %08x %08x %08x\n", objp->orient.m1,objp->orient.m2,objp->orient.m3,
  1144. //                  spp->bytemat[0] << MATRIX_PRECISION,spp->bytemat[1] << MATRIX_PRECISION,spp->bytemat[2] << MATRIX_PRECISION));
  1145. //
  1146. //  mprintf((0, "        %08x %08x %08x    %08x %08x %08x\n", objp->orient.m4,objp->orient.m5,objp->orient.m6,
  1147. //                  spp->bytemat[3] << MATRIX_PRECISION,spp->bytemat[4] << MATRIX_PRECISION,spp->bytemat[5] << MATRIX_PRECISION));
  1148. //
  1149. //  mprintf((0, "        %08x %08x %08x    %08x %08x %08x\n", objp->orient.m7,objp->orient.m8,objp->orient.m9,
  1150. //                  spp->bytemat[6] << MATRIX_PRECISION,spp->bytemat[7] << MATRIX_PRECISION,spp->bytemat[8] << MATRIX_PRECISION));
  1151. //
  1152. //  mprintf((0, "Positn: %08x %08x %08x    %08x %08x %08x\n", objp->pos.x, objp->pos.y, objp->pos.z,
  1153. //       (spp->xo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].x,
  1154. //       (spp->yo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].y,
  1155. //       (spp->zo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].z));
  1156. //  mprintf((0, "Segment: %3i    %3i\n", objp->segnum, spp->segment));
  1157.  
  1158. }
  1159.  
  1160. void extract_shortpos(object *objp, shortpos *spp)
  1161. {
  1162.     int segnum;
  1163.     byte    *sp;
  1164.     int swap_bytes = 1;
  1165.  
  1166.     sp = spp->bytemat;
  1167.  
  1168.     objp->orient.rvec.x = *sp++ << MATRIX_PRECISION;
  1169.     objp->orient.uvec.x = *sp++ << MATRIX_PRECISION;
  1170.     objp->orient.fvec.x = *sp++ << MATRIX_PRECISION;
  1171.     objp->orient.rvec.y = *sp++ << MATRIX_PRECISION;
  1172.     objp->orient.uvec.y = *sp++ << MATRIX_PRECISION;
  1173.     objp->orient.fvec.y = *sp++ << MATRIX_PRECISION;
  1174.     objp->orient.rvec.z = *sp++ << MATRIX_PRECISION;
  1175.     objp->orient.uvec.z = *sp++ << MATRIX_PRECISION;
  1176.     objp->orient.fvec.z = *sp++ << MATRIX_PRECISION;
  1177.  
  1178.     if (swap_bytes) {
  1179.         spp->xo = swapshort(spp->xo);
  1180.         spp->yo = swapshort(spp->yo);
  1181.         spp->zo = swapshort(spp->zo);
  1182.         spp->segment = swapshort(spp->segment);
  1183.         spp->velx = swapshort(spp->velx);
  1184.         spp->vely = swapshort(spp->vely);
  1185.         spp->velz = swapshort(spp->velz);
  1186.     }
  1187.  
  1188.     segnum = spp->segment;
  1189.  
  1190.     Assert((segnum >= 0) && (segnum <= Highest_segment_index));
  1191.  
  1192.     objp->pos.x = (spp->xo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].x;
  1193.     objp->pos.y = (spp->yo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].y;
  1194.     objp->pos.z = (spp->zo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].z;
  1195.  
  1196.     objp->mtype.phys_info.velocity.x = (spp->velx << VEL_PRECISION);
  1197.     objp->mtype.phys_info.velocity.y = (spp->vely << VEL_PRECISION);
  1198.     objp->mtype.phys_info.velocity.z = (spp->velz << VEL_PRECISION);
  1199.  
  1200.     obj_relink(objp-Objects, segnum);
  1201.  
  1202. //  db_printf(( "Matrix: %08x %08x %08x    %08x %08x %08x\n", objp->orient.rvec.x,objp->orient.uvec.x,objp->orient.fvec.x,
  1203. //                  spp->bytemat[0],spp->bytemat[1],spp->bytemat[2]));
  1204. //
  1205. //  db_printf(( "        %08x %08x %08x    %08x %08x %08x\n", objp->orient.rvec.y,objp->orient.uvec.y,objp->orient.fvec.y,
  1206. //                  spp->bytemat[3],spp->bytemat[4],spp->bytemat[5]));
  1207. //
  1208. //  db_printf(( "        %08x %08x %08x    %08x %08x %08x\n", objp->orient.rvec.z,objp->orient.uvec.z,objp->orient.fvec.z,
  1209. //                  spp->bytemat[6],spp->bytemat[7],spp->bytemat[8]));
  1210. //
  1211. //  db_printf(( "Positn: %08x %08x %08x    %08x %08x %08x\n", objp->pos.x, objp->pos.y, objp->pos.z,
  1212. //          (spp->xo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].x, (spp->yo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].y, (spp->zo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].z));
  1213. //  db_printf(( "Segment: %3i    %3i\n", objp->segnum, spp->segment));
  1214.  
  1215. }
  1216.  
  1217. //--unused-- void test_shortpos(void)
  1218. //--unused-- {
  1219. //--unused--    shortpos    spp;
  1220. //--unused-- 
  1221. //--unused--    create_shortpos(&spp, &Objects[0]);
  1222. //--unused--    extract_shortpos(&Objects[0], &spp);
  1223. //--unused-- 
  1224. //--unused-- }
  1225.  
  1226. //  -----------------------------------------------------------------------------
  1227. //  Segment validation functions.
  1228. //  Moved from editor to game so we can compute surface normals at load time.
  1229. // -------------------------------------------------------------------------------
  1230.  
  1231. // ------------------------------------------------------------------------------------------
  1232. //  Extract a vector from a segment.  The vector goes from the start face to the end face.
  1233. //  The point on each face is the average of the four points forming the face.
  1234. void extract_vector_from_segment(segment *sp, vms_vector *vp, int start, int end)
  1235. {
  1236.     int         i;
  1237.     vms_vector  vs,ve;
  1238.  
  1239.     vm_vec_zero(&vs);
  1240.     vm_vec_zero(&ve);
  1241.  
  1242.     for (i=0; i<4; i++) {
  1243.         vm_vec_add2(&vs,&Vertices[sp->verts[Side_to_verts[start][i]]]);
  1244.         vm_vec_add2(&ve,&Vertices[sp->verts[Side_to_verts[end][i]]]);
  1245.     }
  1246.  
  1247.     vm_vec_sub(vp,&ve,&vs);
  1248.     vm_vec_scale(vp,F1_0/4);
  1249.  
  1250. }
  1251.  
  1252. //create a matrix that describes the orientation of the given segment
  1253. void extract_orient_from_segment(vms_matrix *m,segment *seg)
  1254. {
  1255.     vms_vector fvec,uvec;
  1256.  
  1257.     extract_vector_from_segment(seg,&fvec,WFRONT,WBACK);
  1258.     extract_vector_from_segment(seg,&uvec,WBOTTOM,WTOP);
  1259.  
  1260.     //vector to matrix does normalizations and orthogonalizations
  1261.     vm_vector_2_matrix(m,&fvec,&uvec,NULL);
  1262. }
  1263.  
  1264. #ifdef EDITOR
  1265. // ------------------------------------------------------------------------------------------
  1266. //  Extract the forward vector from segment *sp, return in *vp.
  1267. //  The forward vector is defined to be the vector from the the center of the front face of the segment
  1268. // to the center of the back face of the segment.
  1269. void extract_forward_vector_from_segment(segment *sp,vms_vector *vp)
  1270. {
  1271.     extract_vector_from_segment(sp,vp,WFRONT,WBACK);
  1272. }
  1273.  
  1274. // ------------------------------------------------------------------------------------------
  1275. //  Extract the right vector from segment *sp, return in *vp.
  1276. //  The forward vector is defined to be the vector from the the center of the left face of the segment
  1277. // to the center of the right face of the segment.
  1278. void extract_right_vector_from_segment(segment *sp,vms_vector *vp)
  1279. {
  1280.     extract_vector_from_segment(sp,vp,WLEFT,WRIGHT);
  1281. }
  1282.  
  1283. // ------------------------------------------------------------------------------------------
  1284. //  Extract the up vector from segment *sp, return in *vp.
  1285. //  The forward vector is defined to be the vector from the the center of the bottom face of the segment
  1286. // to the center of the top face of the segment.
  1287. void extract_up_vector_from_segment(segment *sp,vms_vector *vp)
  1288. {
  1289.     extract_vector_from_segment(sp,vp,WBOTTOM,WTOP);
  1290. }
  1291. #endif
  1292.  
  1293. void add_side_as_quad(segment *sp, int sidenum, vms_vector *normal)
  1294. {
  1295.     side    *sidep = &sp->sides[sidenum];
  1296.  
  1297.     sidep->type = SIDE_IS_QUAD;
  1298.  
  1299.     #ifdef COMPACT_SEGS
  1300.         normal = normal;        //avoid compiler warning
  1301.     #else
  1302.     sidep->normals[0] = *normal;
  1303.     sidep->normals[1] = *normal;
  1304.     #endif
  1305.  
  1306.     //  If there is a connection here, we only formed the faces for the purpose of determining segment boundaries,
  1307.     //  so don't generate polys, else they will get rendered.
  1308. //  if (sp->children[sidenum] != -1)
  1309. //      sidep->render_flag = 0;
  1310. //  else
  1311. //      sidep->render_flag = 1;
  1312.  
  1313. }
  1314.  
  1315.  
  1316. // -------------------------------------------------------------------------------
  1317. //  Return v0, v1, v2 = 3 vertices with smallest numbers.  If *negate_flag set, then negate normal after computation.
  1318. //  Note, you cannot just compute the normal by treating the points in the opposite direction as this introduces
  1319. //  small differences between normals which should merely be opposites of each other.
  1320. get_verts_for_normal(int va, int vb, int vc, int vd, int *v0, int *v1, int *v2, int *v3, int *negate_flag)
  1321. {
  1322.     int i,j;
  1323.     int v[4],w[4];
  1324.  
  1325.     //  w is a list that shows how things got scrambled so we know if our normal is pointing backwards
  1326.     for (i=0; i<4; i++)
  1327.         w[i] = i;
  1328.  
  1329.     v[0] = va;
  1330.     v[1] = vb;
  1331.     v[2] = vc;
  1332.     v[3] = vd;
  1333.  
  1334.     for (i=1; i<4; i++)
  1335.         for (j=0; j<i; j++)
  1336.             if (v[j] > v[i]) {
  1337.                 int t;
  1338.                 t = v[j];   v[j] = v[i];    v[i] = t;
  1339.                 t = w[j];   w[j] = w[i];    w[i] = t;
  1340.             }
  1341.  
  1342.     Assert((v[0] < v[1]) && (v[1] < v[2]) && (v[2] < v[3]));
  1343.  
  1344.     //  Now, if for any w[i] & w[i+1]: w[i+1] = (w[i]+3)%4, then must swap
  1345.     *v0 = v[0];
  1346.     *v1 = v[1];
  1347.     *v2 = v[2];
  1348.     *v3 = v[3];
  1349.  
  1350.     if ( (((w[0]+3) % 4) == w[1]) || (((w[1]+3) % 4) == w[2]))
  1351.         *negate_flag = 1;
  1352.     else
  1353.         *negate_flag = 0;
  1354.  
  1355. }
  1356.  
  1357. // -------------------------------------------------------------------------------
  1358. void add_side_as_2_triangles(segment *sp, int sidenum)
  1359. {
  1360.     vms_vector  norm;
  1361.     char            *vs = Side_to_verts[sidenum];
  1362.     fix         dot;
  1363.     vms_vector  vec_13;     //  vector from vertex 1 to vertex 3
  1364.  
  1365.     side    *sidep = &sp->sides[sidenum];
  1366.  
  1367.     //  Choose how to triangulate.
  1368.     //  If a wall, then
  1369.     //      Always triangulate so segment is convex.
  1370.     //      Use Matt's formula: Na . AD > 0, where ABCD are vertices on side, a is face formed by A,B,C, Na is normal from face a.
  1371.     //  If not a wall, then triangulate so whatever is on the other side is triangulated the same (ie, between the same absoluate vertices)
  1372.     if (!IS_CHILD(sp->children[sidenum])) {
  1373.         vm_vec_normal(&norm,  &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[2]]]);
  1374.         vm_vec_sub(&vec_13, &Vertices[sp->verts[vs[3]]], &Vertices[sp->verts[vs[1]]]);
  1375.         dot = vm_vec_dot(&norm, &vec_13);
  1376.  
  1377.         //  Now, signifiy whether to triangulate from 0:2 or 1:3
  1378.         if (dot >= 0)
  1379.             sidep->type = SIDE_IS_TRI_02;
  1380.         else
  1381.             sidep->type = SIDE_IS_TRI_13;
  1382.  
  1383.         #ifndef COMPACT_SEGS
  1384.         //  Now, based on triangulation type, set the normals.
  1385.         if (sidep->type == SIDE_IS_TRI_02) {
  1386.             vm_vec_normal(&norm,  &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[2]]]);
  1387.             sidep->normals[0] = norm;
  1388.             vm_vec_normal(&norm, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[2]]], &Vertices[sp->verts[vs[3]]]);
  1389.             sidep->normals[1] = norm;
  1390.         } else {
  1391.             vm_vec_normal(&norm, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[3]]]);
  1392.             sidep->normals[0] = norm;
  1393.             vm_vec_normal(&norm, &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[2]]], &Vertices[sp->verts[vs[3]]]);
  1394.             sidep->normals[1] = norm;
  1395.         }
  1396.         #endif
  1397.     } else {
  1398.         int i,v[4], vsorted[4];
  1399.         int negate_flag;
  1400.  
  1401.         for (i=0; i<4; i++)
  1402.             v[i] = sp->verts[vs[i]];
  1403.  
  1404.         get_verts_for_normal(v[0], v[1], v[2], v[3], &vsorted[0], &vsorted[1], &vsorted[2], &vsorted[3], &negate_flag);
  1405.  
  1406.         if ((vsorted[0] == v[0]) || (vsorted[0] == v[2])) {
  1407.             sidep->type = SIDE_IS_TRI_02;
  1408.             #ifndef COMPACT_SEGS
  1409.             //  Now, get vertices for normal for each triangle based on triangulation type.
  1410.             get_verts_for_normal(v[0], v[1], v[2], 32767, &vsorted[0], &vsorted[1], &vsorted[2], &vsorted[3], &negate_flag);
  1411.             vm_vec_normal(&norm,  &Vertices[vsorted[0]], &Vertices[vsorted[1]], &Vertices[vsorted[2]]);
  1412.             if (negate_flag)
  1413.                 vm_vec_negate(&norm);
  1414.             sidep->normals[0] = norm;
  1415.  
  1416.             get_verts_for_normal(v[0], v[2], v[3], 32767, &vsorted[0], &vsorted[1], &vsorted[2], &vsorted[3], &negate_flag);
  1417.             vm_vec_normal(&norm,  &Vertices[vsorted[0]], &Vertices[vsorted[1]], &Vertices[vsorted[2]]);
  1418.             if (negate_flag)
  1419.                 vm_vec_negate(&norm);
  1420.             sidep->normals[1] = norm;
  1421.             #endif
  1422.         } else {
  1423.             sidep->type = SIDE_IS_TRI_13;
  1424.             #ifndef COMPACT_SEGS
  1425.             //  Now, get vertices for normal for each triangle based on triangulation type.
  1426.             get_verts_for_normal(v[0], v[1], v[3], 32767, &vsorted[0], &vsorted[1], &vsorted[2], &vsorted[3], &negate_flag);
  1427.             vm_vec_normal(&norm,  &Vertices[vsorted[0]], &Vertices[vsorted[1]], &Vertices[vsorted[2]]);
  1428.             if (negate_flag)
  1429.                 vm_vec_negate(&norm);
  1430.             sidep->normals[0] = norm;
  1431.  
  1432.             get_verts_for_normal(v[1], v[2], v[3], 32767, &vsorted[0], &vsorted[1], &vsorted[2], &vsorted[3], &negate_flag);
  1433.             vm_vec_normal(&norm,  &Vertices[vsorted[0]], &Vertices[vsorted[1]], &Vertices[vsorted[2]]);
  1434.             if (negate_flag)
  1435.                 vm_vec_negate(&norm);
  1436.             sidep->normals[1] = norm;
  1437.             #endif
  1438.         }
  1439.     }
  1440. }
  1441.  
  1442. int sign(fix v)
  1443. {
  1444.  
  1445.     if (v > PLANE_DIST_TOLERANCE)
  1446.         return 1;
  1447.     else if (v < -(PLANE_DIST_TOLERANCE+1))     //neg & pos round differently
  1448.         return -1;
  1449.     else
  1450.         return 0;
  1451. }
  1452.  
  1453. // -------------------------------------------------------------------------------
  1454. void create_walls_on_side(segment *sp, int sidenum)
  1455. {
  1456.     int vm0, vm1, vm2, vm3, negate_flag;
  1457.     int v0, v1, v2, v3;
  1458.     vms_vector vn;
  1459.     fix dist_to_plane;
  1460.  
  1461.     v0 = sp->verts[Side_to_verts[sidenum][0]];
  1462.     v1 = sp->verts[Side_to_verts[sidenum][1]];
  1463.     v2 = sp->verts[Side_to_verts[sidenum][2]];
  1464.     v3 = sp->verts[Side_to_verts[sidenum][3]];
  1465.  
  1466.     get_verts_for_normal(v0, v1, v2, v3, &vm0, &vm1, &vm2, &vm3, &negate_flag);
  1467.  
  1468.     vm_vec_normal(&vn, &Vertices[vm0], &Vertices[vm1], &Vertices[vm2]);
  1469.     dist_to_plane = abs(vm_dist_to_plane(&Vertices[vm3], &vn, &Vertices[vm0]));
  1470.  
  1471. //if ((sp-Segments == 0x7b) && (sidenum == 3)) {
  1472. //  mprintf((0, "Verts = %3i %3i %3i %3i, negate flag = %3i, dist = %8x\n", vm0, vm1, vm2, vm3, negate_flag, dist_to_plane));
  1473. //  mprintf((0, "  Normal = %8x %8x %8x\n", vn.x, vn.y, vn.z));
  1474. //  mprintf((0, "   Vert %3i = [%8x %8x %8x]\n", vm0, Vertices[vm0].x, Vertices[vm0].y, Vertices[vm0].z));
  1475. //  mprintf((0, "   Vert %3i = [%8x %8x %8x]\n", vm1, Vertices[vm1].x, Vertices[vm1].y, Vertices[vm1].z));
  1476. //  mprintf((0, "   Vert %3i = [%8x %8x %8x]\n", vm2, Vertices[vm2].x, Vertices[vm2].y, Vertices[vm2].z));
  1477. //  mprintf((0, "   Vert %3i = [%8x %8x %8x]\n", vm3, Vertices[vm3].x, Vertices[vm3].y, Vertices[vm3].z));
  1478. //}
  1479.  
  1480. //if ((sp-Segments == 0x86) && (sidenum == 5)) {
  1481. //  mprintf((0, "Verts = %3i %3i %3i %3i, negate flag = %3i, dist = %8x\n", vm0, vm1, vm2, vm3, negate_flag, dist_to_plane));
  1482. //  mprintf((0, "  Normal = %8x %8x %8x\n", vn.x, vn.y, vn.z));
  1483. //  mprintf((0, "   Vert %3i = [%8x %8x %8x]\n", vm0, Vertices[vm0].x, Vertices[vm0].y, Vertices[vm0].z));
  1484. //  mprintf((0, "   Vert %3i = [%8x %8x %8x]\n", vm1, Vertices[vm1].x, Vertices[vm1].y, Vertices[vm1].z));
  1485. //  mprintf((0, "   Vert %3i = [%8x %8x %8x]\n", vm2, Vertices[vm2].x, Vertices[vm2].y, Vertices[vm2].z));
  1486. //  mprintf((0, "   Vert %3i = [%8x %8x %8x]\n", vm3, Vertices[vm3].x, Vertices[vm3].y, Vertices[vm3].z));
  1487. //}
  1488.  
  1489.     if (negate_flag)
  1490.         vm_vec_negate(&vn);
  1491.  
  1492.     if (dist_to_plane <= PLANE_DIST_TOLERANCE)
  1493.         add_side_as_quad(sp, sidenum, &vn);
  1494.     else {
  1495.         add_side_as_2_triangles(sp, sidenum);
  1496.  
  1497.         //this code checks to see if we really should be triangulated, and
  1498.         //de-triangulates if we shouldn't be.
  1499.  
  1500.         {
  1501.             int         num_faces;
  1502.             int         vertex_list[6];
  1503.             fix         dist0,dist1;
  1504.             int         s0,s1;
  1505.             int         vertnum;
  1506.             side            *s;
  1507.  
  1508.             create_abs_vertex_lists( &num_faces, vertex_list, sp-Segments, sidenum);
  1509.  
  1510.             Assert(num_faces == 2);
  1511.  
  1512.             s = &sp->sides[sidenum];
  1513.  
  1514.             vertnum = min(vertex_list[0],vertex_list[2]);
  1515.  
  1516.             #ifdef COMPACT_SEGS
  1517.             {
  1518.             vms_vector normals[2];
  1519.             get_side_normals(sp, sidenum, &normals[0], &normals[1] );
  1520.             dist0 = vm_dist_to_plane(&Vertices[vertex_list[1]],&normals[1],&Vertices[vertnum]);
  1521.             dist1 = vm_dist_to_plane(&Vertices[vertex_list[4]],&normals[0],&Vertices[vertnum]);
  1522.             }
  1523.             #else
  1524.             dist0 = vm_dist_to_plane(&Vertices[vertex_list[1]],&s->normals[1],&Vertices[vertnum]);
  1525.             dist1 = vm_dist_to_plane(&Vertices[vertex_list[4]],&s->normals[0],&Vertices[vertnum]);
  1526.             #endif
  1527.  
  1528.             s0 = sign(dist0);
  1529.             s1 = sign(dist1);
  1530.  
  1531.             if (s0==0 || s1==0 || s0!=s1) {
  1532.                 sp->sides[sidenum].type = SIDE_IS_QUAD;     //detriangulate!
  1533.                 #ifndef COMPACT_SEGS
  1534.                 sp->sides[sidenum].normals[0] = vn;
  1535.                 sp->sides[sidenum].normals[1] = vn;
  1536.                 #endif
  1537.             }
  1538.  
  1539.         }
  1540.     }
  1541.  
  1542. }
  1543.  
  1544.  
  1545. #ifdef COMPACT_SEGS
  1546.  
  1547. //#define CACHE_DEBUG 1
  1548. #define MAX_CACHE_NORMALS 128
  1549. #define CACHE_MASK 127
  1550.  
  1551. typedef struct ncache_element {
  1552.     short segnum;
  1553.     ubyte sidenum;
  1554.     vms_vector normals[2];
  1555. } ncache_element;
  1556.  
  1557. int ncache_initialized = 0;
  1558. ncache_element ncache[MAX_CACHE_NORMALS];
  1559.  
  1560. #ifdef CACHE_DEBUG
  1561. int ncache_counter = 0;
  1562. int ncache_hits = 0;
  1563. int ncache_misses = 0;
  1564. #endif
  1565.  
  1566. void ncache_init()
  1567. {
  1568.     ncache_flush();
  1569.     ncache_initialized = 1;
  1570. }
  1571.  
  1572. void ncache_flush()
  1573. {
  1574.     int i;
  1575.     for (i=0; i<MAX_CACHE_NORMALS; i++ )    {
  1576.         ncache[i].segnum = -1;
  1577.     }   
  1578. }
  1579.  
  1580.  
  1581.  
  1582. // -------------------------------------------------------------------------------
  1583. int find_ncache_element( int segnum, int sidenum, int face_flags )
  1584. {
  1585.     uint i;
  1586.  
  1587.     if (!ncache_initialized) ncache_init();
  1588.  
  1589. #ifdef CACHE_DEBUG
  1590.     if (((++ncache_counter % 5000)==1) && (ncache_hits+ncache_misses > 0))
  1591.         mprintf(( 0, "NCACHE %d%% missed, H:%d, M:%d\n", (ncache_misses*100)/(ncache_hits+ncache_misses), ncache_hits, ncache_misses ));
  1592. #endif
  1593.  
  1594.     i = ((segnum<<2) ^ sidenum) & CACHE_MASK;
  1595.  
  1596.     if ((ncache[i].segnum == segnum) && ((ncache[i].sidenum&0xf)==sidenum) )    {
  1597.         uint f1;
  1598. #ifdef CACHE_DEBUG
  1599.         ncache_hits++;
  1600. #endif
  1601.         f1 = ncache[i].sidenum>>4;
  1602.         if ( (f1&face_flags)==face_flags )
  1603.             return i;
  1604.         if ( f1 & 1 )
  1605.             uncached_get_side_normal( &Segments[segnum], sidenum, 1, &ncache[i].normals[1] );
  1606.         else
  1607.             uncached_get_side_normal( &Segments[segnum], sidenum, 0, &ncache[i].normals[0] );
  1608.         ncache[i].sidenum |= face_flags<<4;
  1609.         return i;
  1610.     }
  1611. #ifdef CACHE_DEBUG
  1612.     ncache_misses++;
  1613. #endif
  1614.  
  1615.     switch( face_flags )    {
  1616.     case 1: 
  1617.         uncached_get_side_normal( &Segments[segnum], sidenum, 0, &ncache[i].normals[0] );
  1618.         break;
  1619.     case 2:
  1620.         uncached_get_side_normal( &Segments[segnum], sidenum, 1, &ncache[i].normals[1] );
  1621.         break;
  1622.     case 3:
  1623.         uncached_get_side_normals(&Segments[segnum], sidenum, &ncache[i].normals[0], &ncache[i].normals[1] );
  1624.         break;
  1625.     }
  1626.     ncache[i].segnum = segnum;
  1627.     ncache[i].sidenum = sidenum | (face_flags<<4);
  1628.     return i;
  1629. }
  1630.  
  1631. void get_side_normal(segment *sp, int sidenum, int face_num, vms_vector * vm )
  1632. {
  1633.     int i;
  1634.     i = find_ncache_element( sp - Segments, sidenum, 1 << face_num );
  1635.     *vm = ncache[i].normals[face_num];
  1636.     if (0) {
  1637.         vms_vector tmp;
  1638.         uncached_get_side_normal(sp, sidenum, face_num, &tmp );
  1639.         Assert( tmp.x == vm->x );
  1640.         Assert( tmp.y == vm->y );
  1641.         Assert( tmp.z == vm->z );
  1642.     }
  1643. }
  1644.  
  1645. void get_side_normals(segment *sp, int sidenum, vms_vector * vm1, vms_vector * vm2 )
  1646. {
  1647.     int i;
  1648.     i = find_ncache_element( sp - Segments, sidenum, 3 );
  1649.     *vm1 = ncache[i].normals[0];
  1650.     *vm2 = ncache[i].normals[1];
  1651.  
  1652.     if (0) {
  1653.         vms_vector tmp;
  1654.         uncached_get_side_normal(sp, sidenum, 0, &tmp );
  1655.         Assert( tmp.x == vm1->x );
  1656.         Assert( tmp.y == vm1->y );
  1657.         Assert( tmp.z == vm1->z );
  1658.         uncached_get_side_normal(sp, sidenum, 1, &tmp );
  1659.         Assert( tmp.x == vm2->x );
  1660.         Assert( tmp.y == vm2->y );
  1661.         Assert( tmp.z == vm2->z );
  1662.     }
  1663.  
  1664. }
  1665.  
  1666. void uncached_get_side_normal(segment *sp, int sidenum, int face_num, vms_vector * vm )
  1667. {
  1668.     int vm0, vm1, vm2, vm3, negate_flag;
  1669.     char    *vs = Side_to_verts[sidenum];
  1670.  
  1671.     switch( sp->sides[sidenum].type )   {
  1672.     case SIDE_IS_QUAD:
  1673.         get_verts_for_normal(sp->verts[vs[0]], sp->verts[vs[1]], sp->verts[vs[2]], sp->verts[vs[3]], &vm0, &vm1, &vm2, &vm3, &negate_flag);
  1674.         vm_vec_normal(vm, &Vertices[vm0], &Vertices[vm1], &Vertices[vm2]);
  1675.         if (negate_flag)
  1676.             vm_vec_negate(vm);
  1677.         break;
  1678.     case SIDE_IS_TRI_02:
  1679.         if ( face_num == 0 )
  1680.             vm_vec_normal(vm, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[2]]]);
  1681.         else
  1682.             vm_vec_normal(vm, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[2]]], &Vertices[sp->verts[vs[3]]]);
  1683.         break;
  1684.     case SIDE_IS_TRI_13:
  1685.         if ( face_num == 0 )
  1686.             vm_vec_normal(vm, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[3]]]);
  1687.         else
  1688.             vm_vec_normal(vm, &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[2]]], &Vertices[sp->verts[vs[3]]]);
  1689.         break;
  1690.     }
  1691. }
  1692.  
  1693. void uncached_get_side_normals(segment *sp, int sidenum, vms_vector * vm1, vms_vector * vm2 )
  1694. {
  1695.     int vvm0, vvm1, vvm2, vvm3, negate_flag;
  1696.     char    *vs = Side_to_verts[sidenum];
  1697.  
  1698.     switch( sp->sides[sidenum].type )   {
  1699.     case SIDE_IS_QUAD:
  1700.         get_verts_for_normal(sp->verts[vs[0]], sp->verts[vs[1]], sp->verts[vs[2]], sp->verts[vs[3]], &vvm0, &vvm1, &vvm2, &vvm3, &negate_flag);
  1701.         vm_vec_normal(vm1, &Vertices[vvm0], &Vertices[vvm1], &Vertices[vvm2]);
  1702.         if (negate_flag)
  1703.             vm_vec_negate(vm1);
  1704.         *vm2 = *vm1;
  1705.         break;
  1706.     case SIDE_IS_TRI_02:
  1707.         vm_vec_normal(vm1, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[2]]]);
  1708.         vm_vec_normal(vm2, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[2]]], &Vertices[sp->verts[vs[3]]]);
  1709.         break;
  1710.     case SIDE_IS_TRI_13:
  1711.         vm_vec_normal(vm1, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[3]]]);
  1712.         vm_vec_normal(vm2, &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[2]]], &Vertices[sp->verts[vs[3]]]);
  1713.         break;
  1714.     }
  1715. }
  1716.  
  1717. #endif
  1718.  
  1719. // -------------------------------------------------------------------------------
  1720. void validate_removable_wall(segment *sp, int sidenum, int tmap_num)
  1721. {
  1722.     create_walls_on_side(sp, sidenum);
  1723.  
  1724.     sp->sides[sidenum].tmap_num = tmap_num;
  1725.  
  1726. //  assign_default_uvs_to_side(sp, sidenum);
  1727. //  assign_light_to_side(sp, sidenum);
  1728. }
  1729.  
  1730. // -------------------------------------------------------------------------------
  1731. //  Make a just-modified segment side valid.
  1732. void validate_segment_side(segment *sp, int sidenum)
  1733. {
  1734.     if (sp->sides[sidenum].wall_num == -1)
  1735.         create_walls_on_side(sp, sidenum);
  1736.     else
  1737.         // create_removable_wall(sp, sidenum, sp->sides[sidenum].tmap_num);
  1738.         validate_removable_wall(sp, sidenum, sp->sides[sidenum].tmap_num);
  1739.  
  1740.     //  Set render_flag.
  1741.     //  If side doesn't have a child, then render wall.  If it does have a child, but there is a temporary
  1742.     //  wall there, then do render wall.
  1743. //  if (sp->children[sidenum] == -1)
  1744. //      sp->sides[sidenum].render_flag = 1;
  1745. //  else if (sp->sides[sidenum].wall_num != -1)
  1746. //      sp->sides[sidenum].render_flag = 1;
  1747. //  else
  1748. //      sp->sides[sidenum].render_flag = 0;
  1749. }
  1750.  
  1751. extern int check_for_degenerate_segment(segment *sp);
  1752.  
  1753. // -------------------------------------------------------------------------------
  1754. //  Make a just-modified segment valid.
  1755. //      check all sides to see how many faces they each should have (0,1,2)
  1756. //      create new vector normals
  1757. void validate_segment(segment *sp)
  1758. {
  1759.     int side;
  1760.  
  1761.     #ifdef EDITOR
  1762.     check_for_degenerate_segment(sp);
  1763.     #endif
  1764.  
  1765.     for (side = 0; side < MAX_SIDES_PER_SEGMENT; side++)
  1766.         validate_segment_side(sp, side);
  1767.  
  1768. //  assign_default_uvs_to_segment(sp);
  1769. }
  1770.  
  1771. // -------------------------------------------------------------------------------
  1772. //  Validate all segments.
  1773. //  Highest_segment_index must be set.
  1774. //  For all used segments (number <= Highest_segment_index), segnum field must be != -1.
  1775. void validate_segment_all(void)
  1776. {
  1777.     int s;
  1778.  
  1779.     for (s=0; s<=Highest_segment_index; s++)
  1780.         #ifdef EDITOR
  1781.         if (Segments[s].segnum != -1)
  1782.         #endif
  1783.             validate_segment(&Segments[s]);
  1784.  
  1785.     #ifdef EDITOR
  1786.     {
  1787.         int said=0;
  1788.         for (s=Highest_segment_index+1; s<MAX_SEGMENTS; s++)
  1789.             if (Segments[s].segnum != -1) {
  1790.                 if (!said) {
  1791.                     mprintf((0, "Segment %i has invalid segnum.  Bashing to -1.  Silently bashing all others...", s));
  1792.                 }
  1793.                 said++;
  1794.                 Segments[s].segnum = -1;
  1795.             }
  1796.  
  1797.         if (said)
  1798.             mprintf((0, "%i fixed.\n", said));
  1799.     }
  1800.     #endif
  1801.  
  1802.     #ifndef NDEBUG
  1803.     #ifndef COMPACT_SEGS
  1804.     if (check_segment_connections())
  1805.         Int3();     //Get Matt, si vous plait.
  1806.     #endif
  1807.     #endif
  1808. }
  1809.  
  1810.  
  1811. //  ------------------------------------------------------------------------------------------------------
  1812. //  Picks a random point in a segment like so:
  1813. //      From center, go up to 50% of way towards any of the 8 vertices.
  1814. void pick_random_point_in_seg(vms_vector *new_pos, int segnum)
  1815. {
  1816.     int         vnum;
  1817.     vms_vector  vec2;
  1818.  
  1819.     compute_segment_center(new_pos, &Segments[segnum]);
  1820.     vnum = (rand() * MAX_VERTICES_PER_SEGMENT) >> 15;
  1821.     vm_vec_sub(&vec2, &Vertices[Segments[segnum].verts[vnum]], new_pos);
  1822.     vm_vec_scale(&vec2, rand());            //  rand() always in 0..1/2
  1823.     vm_vec_add2(new_pos, &vec2);
  1824. }
  1825.  
  1826.  
  1827. //  ----------------------------------------------------------------------------------------------------------
  1828. //  Set the segment depth of all segments from start_seg in *segbuf.
  1829. //  Returns maximum depth value.
  1830. int set_segment_depths(int start_seg, ubyte *segbuf)
  1831. {
  1832.     int i, curseg;
  1833.     ubyte   visited[MAX_SEGMENTS];
  1834.     int queue[MAX_SEGMENTS];
  1835.     int head, tail;
  1836.     int depth;
  1837.     int parent_depth;
  1838.  
  1839.     depth = 1;
  1840.     head = 0;
  1841.     tail = 0;
  1842.  
  1843.     for (i=0; i<=Highest_segment_index; i++)
  1844.         visited[i] = 0;
  1845.  
  1846.     if (segbuf[start_seg] == 0)
  1847.         return 1;
  1848.  
  1849.     queue[tail++] = start_seg;
  1850.     visited[start_seg] = 1;
  1851.     segbuf[start_seg] = depth++;
  1852.  
  1853.     if (depth == 0)
  1854.         depth = 255;
  1855.  
  1856.     while (head < tail) {
  1857.         curseg = queue[head++];
  1858.         parent_depth = segbuf[curseg];
  1859.  
  1860.         for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) {
  1861.             int childnum;
  1862.  
  1863.             childnum = Segments[curseg].children[i];
  1864.             if (childnum != -1)
  1865.                 if (segbuf[childnum])
  1866.                     if (!visited[childnum]) {
  1867.                         visited[childnum] = 1;
  1868.                         segbuf[childnum] = parent_depth+1;
  1869.                         queue[tail++] = childnum;
  1870.                     }
  1871.         }
  1872.     }
  1873.  
  1874.     return parent_depth+1;
  1875. }
  1876.  
  1877. //--ubyte   Segbuf[MAX_SEGMENTS];
  1878. //--
  1879. //--void ssd_test(void)
  1880. //--{
  1881. //--    int i;
  1882. //--
  1883. //--    for (i=0; i <=Highest_segment_index; i++)
  1884. //--        Segbuf[i] = 1;
  1885. //--
  1886. //--    set_segment_depths(0, Segbuf);
  1887. //--}
  1888.  
  1889.